﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class WorldGenerator : MonoBehaviour
{

	// 可在检查器中看到的变量
	public Material meshMaterial;  // 网格材质
	public float scale;  // 世界比例
	public Vector2 dimensions;  // 世界的尺寸（x: 横向, y: 纵向）
	public float perlinScale;  // 用于生成噪声的比例
	public float waveHeight;  // 波动高度
	public float offset;  // 噪声偏移量
	public float randomness;  // 随机性
	public float globalSpeed;  // 世界移动的速度
	public int startTransitionLength;  // 开始过渡的长度
	public BasicMovement lampMovement;  // 灯光（或方向光）的运动
	public GameObject[] obstacles;  // 障碍物数组
	public GameObject gate;  // 大门对象
	public int startObstacleChance;  // 开始时生成障碍物的概率
	public int obstacleChanceAcceleration;  // 障碍物概率加速
	public int gateChance;  // 大门生成概率
	public int showItemDistance;  // 显示物品的距离
	public float shadowHeight;  // 阴影高度

	// 不可见的变量
	Vector3[] beginPoints;  // 世界各部分的起始点，用于过渡效果

	GameObject[] pieces = new GameObject[2];  // 存储两个世界部分
	Stack<GameObject>[] items = new Stack<GameObject>[2];//储存两个地图的物品
	GameObject currentCylinder;  // 当前生成的世界部分（圆柱体）

	void Start()
	{
		beginPoints = new Vector3[(int)dimensions.x + 1];
		items[0] = new Stack<GameObject>();
		items[1] = new Stack<GameObject>();
		for (int i = 0; i < 2; i++)
		{
			GenerateWorldPiece(i);
		}
	}

	void LateUpdate()
	{
		if (pieces[1] && pieces[1].transform.position.z <= 0)
		{
			Debug.Log(1);
			StartCoroutine(UpdateWorldPieces());
		}


		UpdateAllItems();
	}

	void UpdateAllItems()
	{
		GameObject[] items = GameObject.FindGameObjectsWithTag("Item");

		for (int i = 0; i < items.Length; i++)
		{
			foreach (MeshRenderer renderer in items[i].GetComponentsInChildren<MeshRenderer>())
			{
				// 如果物品距离玩家足够近，则显示该物品
				bool show = items[i].transform.position.z < showItemDistance;

				// 更新阴影
				if (show)
					renderer.shadowCastingMode = (items[i].transform.position.y < shadowHeight) ? ShadowCastingMode.On : ShadowCastingMode.Off;

				// 只有在需要显示物品时才启用其渲染器
				renderer.enabled = show;
			}
		}
	}

	void GenerateWorldPiece(int i)
	{
		pieces[i] = CreateCylinder();
		// items[i] = new List<GameObject>();
		//遍历pieces下的所有物体
		foreach (Transform child in pieces[i].transform)
		{
			if (child.CompareTag("Item"))
			{
				items[i].Push(child.gameObject);
			}
		}
		Debug.Log("第" + i + "个队列里有" + items[i].Count + "个物品");
		pieces[i].transform.Translate(Vector3.forward * (dimensions.y * scale * Mathf.PI) * i);

		UpdateSinglePiece(pieces[i]);
	}

	IEnumerator UpdateWorldPieces()
	{
		Debug.Log(2);
		while (items[0].Count > 0)
		{
			Debug.Log(3);
			GameObject item = items[0].Pop();
			item.transform.SetParent(null);
			PoolMgr.Instance.PushObj(item);
			// items[0].RemoveAt(0);
		}
		// for (int i = 0; i < items[0].Count; i++)
		// {
		// 	Debug.Log(3);
		// 	items[0][i].transform.SetParent(null);
		// 	PoolMgr.Instance.PushObj(items[0][i]);
		// }
		Debug.Log(4);
		Destroy(pieces[0]);

		pieces[0] = pieces[1];
		items[0] = items[1];

		pieces[1] = CreateCylinder();

		pieces[1].transform.position = pieces[0].transform.position + Vector3.forward * (dimensions.y * scale * Mathf.PI);
		pieces[1].transform.rotation = pieces[0].transform.rotation;

		UpdateSinglePiece(pieces[1]);

		yield return 0;
	}

	void UpdateSinglePiece(GameObject piece)
	{
		//移动
		BasicMovement movement = piece.AddComponent<BasicMovement>();
		movement.movespeed = -globalSpeed;

		// 设置旋转速度为灯光的旋转速度
		if (lampMovement != null)
			movement.rotateSpeed = lampMovement.rotateSpeed;

		// 创建地图终点
		GameObject endPoint = new GameObject();
		endPoint.transform.position = piece.transform.position + Vector3.forward * (dimensions.y * scale * Mathf.PI);
		endPoint.transform.parent = piece.transform;
		endPoint.name = "End Point";

		// 改变噪声偏移量
		offset += randomness;

		// 改变障碍物生成概率
		if (startObstacleChance > 5)
			startObstacleChance -= obstacleChanceAcceleration;
	}

	public GameObject CreateCylinder()
	{
		GameObject newCylinder = new GameObject();
		newCylinder.name = "World piece";

		currentCylinder = newCylinder;

		MeshFilter meshFilter = newCylinder.AddComponent<MeshFilter>();
		MeshRenderer meshRenderer = newCylinder.AddComponent<MeshRenderer>();

		// 设置材质
		meshRenderer.material = meshMaterial;
		// 生成网格
		meshFilter.mesh = Generate();

		// 添加与网格匹配的 MeshCollider 组件
		newCylinder.AddComponent<MeshCollider>();

		return newCylinder;
	}

	// 生成新地图网格
	Mesh Generate()
	{

		Mesh mesh = new Mesh();
		mesh.name = "MESH";

		// 创建数组来存储顶点、UV 坐标和三角形
		Vector3[] vertices = null;
		Vector2[] uv = null;
		int[] triangles = null;

		// 创建网格形状并填充数组
		CreateShape(ref vertices, ref uv, ref triangles);

		// 给网格赋值
		mesh.vertices = vertices;
		mesh.uv = uv;
		mesh.triangles = triangles;

		// 重新计算法线
		mesh.RecalculateNormals();

		return mesh;
	}

	void CreateShape(ref Vector3[] vertices, ref Vector2[] uvs, ref int[] triangles)
	{
		int xCount = (int)dimensions.x;  // 在 x 轴上的顶点数量
		int zCount = (int)dimensions.y;  // 在 z 轴上的顶点数量

		vertices = new Vector3[(xCount + 1) * (zCount + 1)];
		uvs = new Vector2[(xCount + 1) * (zCount + 1)];

		int index = 0;

		// 获取圆柱体的半径
		float radius = xCount * scale * 0.5f;

		// 遍历所有顶点
		for (int x = 0; x <= xCount; x++)
		{
			for (int z = 0; z <= zCount; z++)
			{
				// 获取圆柱体的角度
				float angle = x * Mathf.PI * 2f / xCount;

				// 使用角度的余弦和正弦值来设置顶点
				vertices[index] = new Vector3(Mathf.Cos(angle) * radius, Mathf.Sin(angle) * radius, z * scale * Mathf.PI);

				// 更新 UV 坐标
				uvs[index] = new Vector2(x * scale, z * scale);

				// 加入噪声值
				float pX = (vertices[index].x * perlinScale) + offset;
				float pZ = (vertices[index].z * perlinScale) + offset;

				// 将顶点移动到中心位置（保持 z 坐标）并使用 Perlin 噪声调整位置
				Vector3 center = new Vector3(0, 0, vertices[index].z);
				vertices[index] += (center - vertices[index]).normalized * Mathf.PerlinNoise(pX, pZ) * waveHeight;

				// 处理世界部分之间的平滑过渡
				if (z < startTransitionLength && beginPoints[0] != Vector3.zero)
				{
					// 如果是过渡部分，结合 Perlin 噪声和上一个部分的起始点
					float perlinPercentage = z * (1f / startTransitionLength);
					Vector3 beginPoint = new Vector3(beginPoints[x].x, beginPoints[x].y, vertices[index].z);
					vertices[index] = (perlinPercentage * vertices[index]) + ((1f - perlinPercentage) * beginPoint);
				}
				else if (z == zCount)
				{
					// 更新起始点，以确保下一部分的平滑过渡
					beginPoints[x] = vertices[index];
				}

				// 在随机位置生成物品
				if (Random.Range(0, startObstacleChance) == 0 && !(gate == null && obstacles.Length == 0))
					CreateItem(vertices[index], x);

				// 增加顶点索引
				index++;
			}
		}

		// 初始化三角形数组
		triangles = new int[xCount * zCount * 6];  // 每个方格有 2 个三角形，每个三角形由 3 个顶点组成，共 6 个顶点

		// 创建每个方块的基础（三角形的组成更简单）
		int[] boxBase = new int[6];  // 每个正方形面由 6 个顶点组成（两个三角形）

		int current = 0;

		// 遍历 x 轴上的所有位置
		for (int x = 0; x < xCount; x++)
		{
			boxBase = new int[]{
				x * (zCount + 1),
				x * (zCount + 1) + 1,
				(x + 1) * (zCount + 1),
				x * (zCount + 1) + 1,
				(x + 1) * (zCount + 1) + 1,
				(x + 1) * (zCount + 1),
			};

			// 遍历 z 轴上的所有位置
			for (int z = 0; z < zCount; z++)
			{
				// 增加顶点索引并创建三角形
				for (int i = 0; i < 6; i++)
				{
					boxBase[i] = boxBase[i] + 1;
				}

				// 使用六个顶点填充三角形
				for (int j = 0; j < 6; j++)
				{
					triangles[current + j] = boxBase[j] - 1;
				}

				// 增加当前索引
				current += 6;
			}
		}
	}

	void CreateItem(Vector3 vert, int x)
	{
		// 获取圆柱体的中心位置，但使用顶点的 z 坐标
		Vector3 zCenter = new Vector3(0, 0, vert.z);

		// 检查生成物品的正确位置
		if (zCenter - vert == Vector3.zero || x == (int)dimensions.x / 4 || x == (int)dimensions.x / 4 * 3)
			return;
		Debug.Log(gate.name);
		GameObject newItem = PoolMgr.Instance.GetObj((UnityEngine.Random.Range(0, gateChance) == 0) ? gate.name : obstacles[Random.Range(0, obstacles.Length)].name);

		// 旋转物品使其朝向中心
		// newItem.transform.rotation = Quaternion.LookRotation(zCenter - vert, Vector3.up);
		// 计算指向中心的方向向量（头顶朝向）
		Vector3 upDirection = zCenter - vert;
		// 计算与上方向垂直的前方向（避免共线）
		Vector3 forwardDirection = Vector3.Cross(upDirection, Vector3.right).normalized;
		// 设置旋转：前方向为垂直于中心方向的向量，上方向指向中心
		newItem.transform.rotation = Quaternion.LookRotation(forwardDirection, upDirection);
		// 设置物品位置
		newItem.transform.position = vert;

		// 将物品作为当前圆柱体的子物体，确保它与世界一起移动
		newItem.transform.SetParent(currentCylinder.transform, false);
		newItem.tag = "Item";
	}

	public Transform GetWorldPiece()
	{
		return pieces[0].transform;
	}

}
